


#include <sstream>
#include "catdoors.h"
#include "expdoors.h"



using namespace std;



// CatDoor ::



CatDoor::CatDoor( Subject *subj )
{
    if( subj )
    {
        m_Subjects.push_back(subj);

        // create the text
        ostringstream oss;
        const Door *door = static_cast <const Door *> (subj);
        oss << "the door number " << int( door->getNumber() );
        m_Text = oss.str(); 
    }
}



Category *CatDoor::createCategory( Subject *door )
{
    return new CatDoor( door );
}



bool CatDoor::empty(Subject *owner)
{
    return false;
}



bool CatDoor::one(Subject *owner)
{
    return true;
}



uint8_t CatDoor::getCount(Subject *owner)
{
    return 1;
}



void CatDoor::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    // this category generates expressions only if the owner is not the subject
    if( *getSubjects(owner).begin() != owner )
    {        
        if( ExpAllSafe::complexity() <= level )
            owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
        if( ExpAllTellTruth::complexity() <= level )
            owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
    }
}



// CatThisDoor ::



CatThisDoor::CatThisDoor() :
    CatDoor( NULL )
{
    m_Text = "this door";
}



Category *CatThisDoor::createCategory()
{
    return new CatThisDoor();
}



void CatThisDoor::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    if( ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( ExpAllTellTruth::complexity() <= level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
}



const CollectionSubjects &CatThisDoor::getSubjects( Subject *subj )
{
    if( subj )
    {
        m_Subjects.clear();
        m_Subjects.push_back(subj);
    }
    return m_Subjects;
}



// CatColorDoors ::



CatColorDoors::CatColorDoors( CollectionSubjects &doors, Color::eColor col )
    : CatColor( doors, col )
{
    ostringstream oss;
    oss << "the " << m_Color.getText() << (one() ? " door" : " doors");
    m_Text = oss.str();
}



Category *CatColorDoors::createCategory( CollectionSubjects &doors, Color::eColor col, Color::eColor max_col )
{
    // try creating the collection
    Category *cat = new CatColorDoors( doors, col );
    if( cat->empty() || cat->getCount() == doors.size() )
    {
        delete cat;
        return NULL;
    }
    else
        return cat; 
}



void CatColorDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    if( ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( !one() && ExpAllTraps::complexity() <= level )
        owner->addExpression( ExpAllTraps::createExpression( this, owner ) );
        
    if( ExpAllTellTruth::complexity() <= level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
        
    if( !one() && ExpAllLie::complexity() <= level )
        owner->addExpression( ExpAllLie::createExpression( this, owner ) );
        
    if( ExpSafeOrTraps::complexity() <= level )
        owner->addExpression( ExpSafeOrTraps::createExpression( this, owner ) );
        
    if( ExpTellTruthOrLie::complexity() <= level )
        owner->addExpression( ExpTellTruthOrLie::createExpression( this, owner ) );
}



// CatEvenDoors ::



CatEvenDoors::CatEvenDoors( CollectionSubjects &doors )
{
    // fill in the collection
    CollectionSubjects::iterator id = doors.begin(), id_end = doors.end();
    for( ; id != id_end; ++id )
    {
        Door *door = static_cast <Door*> (*id);
        if( door->isEven() )
            m_Subjects.push_back( door );
    }
    if(!empty())
    {
        ostringstream oss;
        oss << "the even " << (one() ? "door" : "doors");
        m_Text = oss.str();
    }
}



Category *CatEvenDoors::createCategory( CollectionSubjects &doors )
{
    Category *cat = new CatEvenDoors( doors );
    if( cat->empty() )
    {
        delete cat;
        return NULL;
    }
    else
        return cat;    
}



void CatEvenDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    const uint8_t complexity = 10;
    if( complexity + ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( !one() && complexity + ExpAllTraps::complexity() <= level )
        owner->addExpression( ExpAllTraps::createExpression( this, owner ) );
        
    if( complexity + ExpAllTellTruth::complexity() <= level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
        
    if( !one() && complexity + ExpAllLie::complexity() <= level )
        owner->addExpression( ExpAllLie::createExpression( this, owner ) );
        
    if( complexity + ExpSafeOrTraps::complexity() <= level )
        owner->addExpression( ExpSafeOrTraps::createExpression( this, owner ) );
        
    if( complexity + ExpTellTruthOrLie::complexity() <= level )
        owner->addExpression( ExpTellTruthOrLie::createExpression( this, owner ) );
}



// CatOddDoors ::



CatOddDoors::CatOddDoors( CollectionSubjects &doors )
{
    // fill in the collection
    for( CollectionSubjects::iterator idoor = doors.begin(); idoor != doors.end(); ++idoor )
    {
        Door *door = static_cast <Door*> (*idoor);
        if( !door->isEven() )
            m_Subjects.push_back( door );
    }
    if(!empty())
    {
        ostringstream oss;
        oss << "the odd " << (one() ? "door" : "doors");
        m_Text = oss.str();
    }
}



Category *CatOddDoors::createCategory( CollectionSubjects &doors )
{
    Category *cat = new CatOddDoors( doors );
    if( cat->empty() )
    {
        delete cat;
        return NULL;
    }
    else
        return cat;    
}



// CatAllDoors ::



CatAllDoors::CatAllDoors( CollectionSubjects &doors ) :
    CatAll( doors )
{
    m_Text = "the doors";
}



Category *CatAllDoors::createCategory( CollectionSubjects &doors )
{
    return new CatAllDoors( doors );
}



void CatAllDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    if( ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( ExpAllTraps::complexity() <= level )
        owner->addExpression( ExpAllTraps::createExpression( this, owner ) );
        
    if( ExpAllTellTruth::complexity() <= level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
        
    if( ExpAllLie::complexity() <= level )
        owner->addExpression( ExpAllLie::createExpression( this, owner ) );
        
    if( ExpSafeOrTraps::complexity() <= level )
        owner->addExpression( ExpSafeOrTraps::createExpression( this, owner ) );
        
    if( ExpTellTruthOrLie::complexity() <= level )
        owner->addExpression( ExpTellTruthOrLie::createExpression( this, owner ) );
}



// CatTrapDoors ::



CatTrapDoors::CatTrapDoors( CollectionSubjects &doors ) :
    CatMutable( doors )
{
    refill();
    m_Text = "the doors that have traps";
}



Category *CatTrapDoors::createCategory( CollectionSubjects &doors )
{
     Category *cat = new CatTrapDoors( doors );
     if( cat->empty() )
     {
         delete cat;
         return NULL;
     }
     else
         return cat;
}



void CatTrapDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    const uint8_t complexity = 20;
    if( complexity + ExpAllTellTruth::complexity() <= level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
        
    if( complexity + ExpAllLie::complexity() <= level )
        owner->addExpression( ExpAllLie::createExpression( this, owner ) );
         
    if( complexity + ExpTellTruthOrLie::complexity() <= level )
        owner->addExpression( ExpTellTruthOrLie::createExpression( this, owner ) );
}



void CatTrapDoors::refill()
{
    m_Subjects.clear();
    
    for( CollectionSubjects::const_iterator idoor = m_pBaseSubjects->begin(); idoor != m_pBaseSubjects->end(); ++idoor )
    {
        Door *door = static_cast <Door*> (*idoor);
        if( !door->isSafe() )
            m_Subjects.push_back( door );
    }
}



// CatSafeDoors ::



CatSafeDoors::CatSafeDoors( CollectionSubjects &doors )
    : CatMutable( doors )
{
    refill();
    m_Text = "the safe doors";
}



Category *CatSafeDoors::createCategory( CollectionSubjects &doors )
{
    return new CatSafeDoors( doors );
}



void CatSafeDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    const uint8_t complexity = 20;
    if( complexity + ExpAllTellTruth::complexity() < level )
        owner->addExpression( ExpAllTellTruth::createExpression( this, owner ) );
        
    if( complexity + ExpAllLie::complexity() < level )
        owner->addExpression( ExpAllLie::createExpression( this, owner ) );
         
    if( complexity + ExpTellTruthOrLie::complexity() < level )
        owner->addExpression( ExpTellTruthOrLie::createExpression( this, owner ) );
}



void CatSafeDoors::refill()
{
    m_Subjects.clear();
    
    for( CollectionSubjects::const_iterator idoor = m_pBaseSubjects->begin(); idoor != m_pBaseSubjects->end(); ++idoor )
    {
        Door *door = static_cast <Door*> (*idoor);
        if( door->isSafe() )
            m_Subjects.push_back( door );
    }
}



// CatTruthDoors ::



CatTruthDoors::CatTruthDoors( CollectionSubjects &doors ) :
    CatTruth( doors )
{
    m_Text = "the doors that tell truth";    
}



Category *CatTruthDoors::createCategory( CollectionSubjects &doors )
{
    Category *cat = new CatTruthDoors( doors );
    if( cat->empty() )
    {
        delete cat;
        return NULL;
    }
    else
        return cat;
}



void CatTruthDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    const uint8_t complexity = 30;
    if( complexity + ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( complexity + ExpAllTraps::complexity() <= level )
        owner->addExpression( ExpAllTraps::createExpression( this, owner ) );
       
    if( complexity + ExpSafeOrTraps::complexity() <= level )
        owner->addExpression( ExpSafeOrTraps::createExpression( this, owner ) );
}



// CatLyingDoors ::



CatLyingDoors::CatLyingDoors( CollectionSubjects &doors ) :
    CatLying( doors )
{
    m_Text = "the doors that lie";
}



Category *CatLyingDoors::createCategory( CollectionSubjects &doors )
{
    Category *cat = new CatLyingDoors( doors );
    if( cat->empty() )
    {
        delete cat;
        return NULL;
    }
    else
        return cat;
}



void CatLyingDoors::generate( CollectionSubjects &subs, Subject *owner, uint8_t level )
{
    const uint8_t complexity = 30;
    if( complexity + ExpAllSafe::complexity() <= level )
        owner->addExpression( ExpAllSafe::createExpression( this, owner ) );
        
    if( complexity + ExpAllTraps::complexity() <= level )
        owner->addExpression( ExpAllTraps::createExpression( this, owner ) );
       
    if( complexity + ExpSafeOrTraps::complexity() <= level )
        owner->addExpression( ExpSafeOrTraps::createExpression( this, owner ) );
}
